package com.hawk.eye.server.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hawk.eye.api.storage.dto.LogMessageDTO;
import com.hawk.eye.client.toolkit.HawkEyeLogger;
import com.hawk.eye.common.utils.*;
import com.hawk.eye.framework.utils.*;
import com.hawk.eye.framework.utils.spring.SpringUtils;
import com.hawk.eye.server.constant.AlarmConstant;
import com.hawk.eye.server.constant.CreateProblemStatusEnum;
import com.hawk.eye.server.convert.AlarmLogConvert;
import com.hawk.eye.server.delegate.LogMessageStorageDelegate;
import com.hawk.eye.server.domain.dto.req.DenoiseRuleReqDTO;
import com.hawk.eye.server.domain.dto.req.UpgradesRuleReqDTO;
import com.hawk.eye.server.domain.dto.resp.TemplateRespDTO;
import com.hawk.eye.server.domain.po.AlarmBaseLog;
import com.hawk.eye.server.domain.po.ServiceConfig;
import com.hawk.eye.server.mapper.AlarmBaseLogMapper;
import com.hawk.eye.server.service.ITemplateService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.hawk.eye.server.service.IAlarmBaseLogService;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;

/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author salad
 * @date 2023-10-23
 */
@Service
@RequiredArgsConstructor
public class AlarmBaseLogServiceImpl extends ServiceImpl<AlarmBaseLogMapper, AlarmBaseLog> implements IAlarmBaseLogService {

    private final AlarmBaseLogMapper alarmBaseLogMapper;

    private final LogMessageStorageDelegate alarmLogStorageDelegate;

    private final ITemplateService templateService;

    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

    @Override
    public LogMessageDTO resolveLogMessage(ServiceConfig serviceConfig, Map<String, Object> alarmLogAsMap) {
        LogMessageDTO dataDTO = new LogMessageDTO();
        dataDTO.setServiceId(serviceConfig.getId());
        dataDTO.setChargeUserId(serviceConfig.getChargeUserId());
        Object timestamp = alarmLogAsMap.get("@timestamp");
        if(timestamp != null){
            try{
                dataDTO.setAlarmTime(LocalDateTime.from(formatter.parse((String) timestamp)));
            }catch (Exception e){
                HawkEyeLogger.errorWithSkipSend(this.getClass(), "日志中的[@timestamp]解析失败，请确认日期格式是否为：yyyy-MM-dd HH:mm:ss.SSS");
                dataDTO.setAlarmTime(LocalDateTime.now());
            }
        }else{
            dataDTO.setAlarmTime(LocalDateTime.now());
        }
        dataDTO.setServiceName(StringUtil.getIfPresent(alarmLogAsMap.get("serviceName")));
        dataDTO.setErrorFileName(StringUtil.getIfPresent(alarmLogAsMap.get("errorFileName")));
        dataDTO.setStackHash(StringUtil.getIfPresent(alarmLogAsMap.get("stackHash")));
        dataDTO.setRequestUri(StringUtil.getIfPresent(alarmLogAsMap.get("requestUri")));
        dataDTO.setTraceId(StringUtil.getIfPresent(alarmLogAsMap.get("tid"), "N/A"));
        return dataDTO;
    }

    @Override
    public String getUpgradesAlarm(Map<String, Object> alarmLogAsMap, ServiceConfig serviceConfig, LogMessageDTO logMessageDTO) {
        UpgradesRuleReqDTO upgradesRuleReqDTO = new UpgradesRuleReqDTO(serviceConfig.getUpgradesCount());
        long count = getCountByStackHash(logMessageDTO.getStackHash()) + 1;
        int threshold = upgradesRuleReqDTO.getThreshold();
        if (upgradesRuleReqDTO.getThreshold() == null || upgradesRuleReqDTO.getThreshold() == 0) {
            return AlarmConstant.UPGRADES[2];
        }
        int one = threshold;
        int two = 2 * threshold;
        int three = 3 * threshold;
        if (count > 0 && count <= one) {
            return AlarmConstant.UPGRADES[0];
        }
        if (count > one && count <= two) {
            return AlarmConstant.UPGRADES[1];
        }
        if (count > two && count <= three) {
            return AlarmConstant.UPGRADES[2];
        }
        if (count > three) {
            return AlarmConstant.UPGRADES[2];
        }
        return AlarmConstant.UPGRADES[0];
    }

    @Override
    public boolean silenceAlarm(ServiceConfig serviceConfig, LogMessageDTO logMessageDTO) {
        DenoiseRuleReqDTO denoiseRuleReqDTO = JsonUtil.parse(serviceConfig.getDenoiseRule(), DenoiseRuleReqDTO.class);
        ExceptionUtils.isEmptyThrow(denoiseRuleReqDTO, "降噪规则解析失败，请检查服务[{}]的降噪配置是否正确", serviceConfig.getServiceCnName());
        if (denoiseRuleReqDTO.getDenoisePeriod() == null || denoiseRuleReqDTO.getDenoisePeriod() <= 0) {
            return false;
        }
        LocalDateTime alarmTime = logMessageDTO.getAlarmTime();
        LocalDateTime start = alarmTime.minusMinutes(denoiseRuleReqDTO.getDenoisePeriod());
        long count = SpringUtils.getAopProxy(this).getCountByPeriod(logMessageDTO, start, alarmTime);
        return count > denoiseRuleReqDTO.getDenoiseCount();
    }


    @Override
    public long getCountByStackHash(String stackHash) {
        return alarmBaseLogMapper.getCountByStackHash(stackHash);
    }

    @Override
    public long getCountByPeriod(LogMessageDTO logMessageDTO, LocalDateTime start, LocalDateTime end) {
        System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
        if (StringUtil.isBlank(logMessageDTO.getStackHash())) {
            return 0;
        }
        LambdaQueryWrapper<AlarmBaseLog> wrapper = Wrappers.<AlarmBaseLog>lambdaQuery();
        wrapper.eq(AlarmBaseLog::getStackHash, logMessageDTO.getStackHash())
                .ge(AlarmBaseLog::getAlarmTime, start)
                .le(AlarmBaseLog::getAlarmTime, end);
        return count(wrapper);
    }

    @Override
    public void saveLogMessage(LogMessageDTO messageDTO, TemplateRespDTO template, Map<String, Object> alarmLogAsMap) {
        AlarmBaseLog baseLog = AlarmLogConvert.INSTANCE.to(messageDTO);
        baseMapper.insert(baseLog);
        Map<String, Object> logMessage = templateService.filtrationLogMessageByTemplate(template, alarmLogAsMap);
        messageDTO.setBaseAlarmId(baseLog.getId());
        alarmLogStorageDelegate.getAlarmLogStorage().saveLogMessage(messageDTO, logMessage);
    }

    @Override
    public Boolean updateProblemStatus(Long baseAlarmId, CreateProblemStatusEnum createProblemStatusEnum) {
        ExceptionUtils.isEmptyThrow(baseAlarmId, "参数{}不允许为空", "baseAlarmId");
        AlarmBaseLog baseLog = this.getById(baseAlarmId);
        baseLog.setIsCreateProblem(createProblemStatusEnum.getValue());
        return this.updateById(baseLog);
    }

}
